#include <iostream>
#include <stdlib.h>
#include <bitset>
#include "my.h"
#include "Element.hpp"

using namespace std;

void	obit(void* data, size_t i)
{
  static unsigned int j = 0;

  ++j;
  cout << i << ":" << bitset<8>(static_cast<char*>(data)[i]) << "  ";
  if (j == 4)
    {
      j = 0;
      cout << endl;
    }
}

Element::Element() : _data(NULL), _nbParts(0)
{
  // infos concernant l'id obj
  ElmInfo       id;
  id.size = ID_SIZE;
  id.start = 0;
  _elmStruct.push_back(id);
  // infos concernant l'affichage (visible ou non)
  ElmInfo	vs;
  vs.size = VS_SIZE;
  vs.start = id.size;
  _elmStruct.push_back(vs);
  // infos concernant le refresh (à updater ou non)
  ElmInfo	nr;
  nr.size = NR_SIZE;
  nr.start = vs.start + vs.size;
  _elmStruct.push_back(nr);

  // Calcul de la taille finale
  _partSize = 0;
  for(unsigned int i = 0; i < _elmStruct.size(); ++i)
    {
      _partSize += _elmStruct[i].size;
      _elmStruct[i].mask = this->getMask(_elmStruct[i]);
    }
  _partChars = (_partSize / 8) + 1;

  // Création du masque de complément
  _invMask = 0;
  for(unsigned int i = 0; i < _partSize; ++i)
    _invMask = (_invMask << 1) + 1;

  // DEbug bin
  /*
  size_t elmstructsIZE = this->_elmStruct.size() * sizeof(this->_elmStruct[0]);

  for (size_t i = 0;i < elmstructsIZE; ++i)
  obit(static_cast<void*>(&_elmStruct), i);*/
}

void		Element::setDim(size_t dim)
{
  if (_nbParts < dim || _nbParts > 2*dim)
    {
      if ((_data = realloc(_data, dim * _partChars)) != NULL)
	{
	  std::cout << "Allocated " << dim * _partChars << " bytes for "
		    << dim << " elements from one with " << _nbParts << ".\n";
	  _nbParts = dim;
	}
      else
	{
	  std::cout << "Failed Allocation !!!\n";
	  _nbParts = 0;
	}
    }
}

readType	Element::getMask(ElmInfo elm) const
{
  readType	ret = 0;
  for (unsigned int i = 0; i < elm.size; ++i)
    {
      ret = (ret << 1) + 1;
    }
  ret <<= elm.start;
  return ret;
}

size_t		Element::getDim() const
{
  return _nbParts;
}

void		Element::memset_all()
{
  for (size_t s = 0;s < _nbParts; ++s)
    {
      this->set(s, 0);
    }
}

void		Element::set(size_t num, readType data)
{
  (static_cast<readType*>(_data))[num * _partChars] = data;
}

readType	Element::get(size_t num, ElementRef part) const
{
  
  return ((this->_elmStruct[part]).mask & ((static_cast<readType*>(_data))[num * _partChars]))
    >> (this->_elmStruct[part]).start;
}

void           Element::set(size_t num, ElementRef part, readType data)
{
  (static_cast<readType*>(_data))[num * _partChars] = 
    (((static_cast<readType*>(_data))[num * _partChars]) & (_invMask ^ this->_elmStruct[part].mask))
    + (data << this->_elmStruct[part].start);
}

readType	Element::get(size_t num) const
{
  return (static_cast<readType*>(_data))[num * _partChars];
}

void		Element::dump() const
{
  std::cout << "--------------------------"
	    << "DUMP:" << _nbParts * _partChars
	    << "o--------------------------\n";
  my_showmem(static_cast<char*>(_data), _nbParts * _partChars);
}

void		Element::dump2() const
{
  unsigned int  mod = 0;
  unsigned int  per_line = 5;

  std::cout << "--------------------------"
	    << "DUMP:" << _nbParts * _partChars
	    << "o--------------------------\n";
  for (unsigned int i = 0; i < (_nbParts * _partChars); ++i)
    {
      std::cout << i << ":" << std::bitset<8>(static_cast<char*>(_data)[i]);
      if (i / per_line > mod)
	{
	  mod = i / per_line;
	  std::cout << std::endl;
	}
      else
	std::cout << "  ";
    }
  std::cout << "\n--------------------------"
	    << "DUMP:END"
	    << "--------------------------\n";
}
